<template>
  <div>
    <div
      id="go-graph-diagram"
      style="width: 100%;height: 700px;border: 1px solid #d8d8d8;"
    ></div>
    <button @click="refresh">刷新</button>
  </div>
</template>
<script>
import go from 'gojs'
let self = null
export default {
  data () {
    return {
      diagram: null,
      $: null,
      opacity: 1,
      down: true,
      // 定时器
      timer: null
    }
  },
  mounted () {
    self = this
    // 初始化 Gojs 实例
    this.initDiagram()
  },
  methods: {
    // 刷新
    refresh () {
      this.initDiagram()
    },
    initDiagram () {
      // this.diagram = null
      if (this.diagram && this.diagram.div) this.diagram.div = null
      this.$ = go.GraphObject.make
      this.diagram = this.$(go.Diagram, 'go-graph-diagram')
      this.diagram.toolManager.hoverDelay = 100
      this.setNodeStyle()
      this.setLinkStyle()
      this.setModel()

      // // 将图表在画布中居中显示
      this.diagram.initialContentAlignment = go.Spot.Center
      this.doubleTreeLayout(this.diagram)

      // 点击最外层时将所有选中状态取消
      this.diagram.click = (diagram) => {
        this.diagram.nodes.map(node => {
          node.isShadowed = false
          let pic = node.findObject('Picture')
          pic.source = node.jb.source
          // node.findLinksConnected().each(function (l) { l.isHighlighted = false })
          this.setDefaultLineColor(node)
        })
      }
    },
    // 分开左右节点
    separatePartsByLayout (diagram, bottomParts, topParts) {
      var root = diagram.findNodeForKey('Root')
      if (root === null) return
      // 根节点由两个子树共享！
      bottomParts.add(root)
      topParts.add(root)
      // 查看根节点的所有直接子节点
      root.findTreeChildrenNodes().each(function (child) {
        // 这个子节点是朝什么方向成长的
        var dir = child.data.dir
        var coll = (dir === 'bottom') ? bottomParts : topParts
        // 从这个子节点开始添加整个子树
        coll.addAll(child.findTreeParts())
        // 并将根节点的链接添加到此子节点
        coll.add(child.findTreeParentLink())
      })
    },
    // 双层树展示
    doubleTreeLayout (diagram) {
      // Within this function override the definition of '$' from jQuery:
      diagram.startTransaction('Double Tree Layout')

      // 根据方向将节点和链接拆分为两组
      var bottomParts = new go.Set(/* go.Part */)
      var topParts = new go.Set(/* go.Part */)
      this.separatePartsByLayout(diagram, bottomParts, topParts)
      // 但是根节点将在两个集合中

      // 在节点和链接的不同子集上创建并执行两个树布局，每个方向一个，不移动根节点
      var layout1 =
        this.$(go.TreeLayout, {
          angle: 90,
          arrangement: go.TreeLayout.ArrangementFixedRoots,
          setsPortSpot: false
        })

      var layout2 =
        this.$(go.TreeLayout, {
          angle: 270,
          arrangement: go.TreeLayout.ArrangementFixedRoots,
          setsPortSpot: false
        })

      layout1.doLayout(bottomParts)
      layout2.doLayout(topParts)

      diagram.commitTransaction('Double Tree Layout')
    },
    // 设置 model
    setModel () {
      let models = [
        // 这些节点数据是缩进的，但不是根据树中的深度嵌套的
        {
          text: '路由器',
          key: 'Root',
          color: 'pink',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四',
          name: '一二三四五六七三四五六七八九十',
          parent_name: '一二三二三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'bottom1',
          parent: 'Root',
          dir: 'bottom',
          color: '#fe5722',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五八九十',
          name: '一二三四五六七五六七八九十',
          parent_name: '一二三四五六五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf1',
          parent: 'bottom1',
          color: '#fe5722',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六十',
          name: '一二三四五六七八九四五六七八九十',
          parent_name: '一二三四五六九十一二三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf2',
          parent: 'bottom1',
          color: '#fe5722',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六七十',
          name: '一二三四五六九十一二三四五六七八九十',
          parent_name: '一二三四五六三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'bottom2',
          parent: 'bottom1',
          color: '#fe5722',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五九十',
          name: '一二三四五六七八九十一二三四五十',
          parent_name: '一二七八九十一二三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf3',
          parent: 'bottom2',
          color: '#fe5722',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五八九十',
          name: '一二三四五六七八九十一二三八九十',
          parent_name: '一二三十一二三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf4',
          parent: 'leaf3',
          color: '#FEA200',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六七八九十',
          name: '一二三四五六二三四五六七八九十',
          parent_name: '一二三四五六七八四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf5',
          parent: 'leaf3',
          color: '#FEA200',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六七',
          name: '一二三四五一二三四五六七八九十',
          parent_name: '一二三四五六七八九十五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf6',
          parent: 'leaf1',
          color: '#FEA200',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六七八九十',
          name: '一二三四五六七二三四五六七八九十',
          parent_name: '一二三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf4',
          parent: 'bottom2',
          color: '#fe5722',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六七八九十',
          name: '一二三四五六六七八九十',
          parent_name: '一二三七八九十一二三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'top1',
          parent: 'Root',
          dir: 'top',
          color: 'green',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六七八九十',
          name: '一二三四五六七八九十一二三四五九十',
          parent_name: '一二三四五六七三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'top2',
          parent: 'top1',
          color: 'green',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六七八九十',
          name: '一二三四五六七八九十',
          parent_name: '一二三四五三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf5',
          parent: 'top2',
          color: 'green',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四九十',
          name: '一二三四五六八九十',
          parent_name: '一二三四五七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf6',
          parent: 'top2',
          color: 'green',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二九十',
          name: '一二三七八九十',
          parent_name: '一二六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf7',
          parent: 'top2',
          color: 'green',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六七八九十',
          name: '一二三四五六七八九十一二三四五六七八九十',
          parent_name: '一二三四五六七八九十一二三四五六七八九十',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf8',
          parent: 'top1',
          color: 'green',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五九十',
          name: '一二三四五六',
          parent_name: '一二三四',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        },
        {
          key: 'leaf9',
          parent: 'top1',
          color: 'green',
          textColor: '#666',
          lineColor: '#2e2e2e',
          ip: '123.123.123.123',
          state: '正常',
          layer: '一二三四五六七八九十',
          name: '一二三四五六七',
          parent_name: '一二三四五',
          source: require('../../assets/changemachine/icon-changemachine-default-cyan.png'),
          hlSource: require('../../assets/changemachine/icon-changemachine-selected-cyan.png')
        }
      ]

      this.diagram.model = new go.TreeModel(models)
    },
    textStyle () {
      return {
        font: '12px 微软雅黑',
        stroke: 'white',
        wrap: go.TextBlock.WrapFit
        // WrapDesiredSize: 100
      }
    },
    tooltipValueFont () {
      return {
        font: '16px 微软雅黑',
        stroke: 'white',
        wrap: go.TextBlock.WrapFit
        // WrapDesiredSize: 100
      }
    },
    tooltipLabelFont () {
      return {
        font: '12px 微软雅黑',
        stroke: '#ccc',
        wrap: go.TextBlock.WrapFit
        // WrapDesiredSize: 100
      }
    },
    tooltipNameFont () {
      return {
        font: 'normal small-caps bold 16px 微软雅黑 MicrosoftYaHeiUI-Bold',
        stroke: 'white',
        wrap: go.TextBlock.WrapFit
        // WrapDesiredSize: 100
      }
    },
    setActiveLineColor (node) {
      if (node.jb.lineColor === '#2e2e2e') {
        self.diagram.model.setDataProperty(node.jb, 'lineColor', '#186b6d')
      }

      if (node.jb.lineColor === '#e10000') {
        self.diagram.model.setDataProperty(node.jb, 'lineColor', '#c00000')
      }

      if (node.jb.wranColor === 'rgba(255,0,0,0.3)') {
        self.diagram.model.setDataProperty(node.jb, 'wranColor', 'rgba(255,0,0,0.2)')
      }
    },
    setDefaultLineColor (node) {
      if (node.jb.lineColor === '#186b6d') {
        this.diagram.model.setDataProperty(node.jb, 'lineColor', '#2e2e2e')
      }

      if (node.jb.lineColor === '#c00000') {
        this.diagram.model.setDataProperty(node.jb, 'lineColor', '#e10000')
      }

      if (node.jb.wranColor === 'rgba(255,0,0,0.2)') {
        this.diagram.model.setDataProperty(node.jb, 'wranColor', 'rgba(255,0,0,0.3)')
      }
    },
    // 设置节点样式
    setNodeStyle () {
      // 定义节点
      this.diagram.nodeTemplate =
        this.$(go.Node, 'Auto', {
          // 是否显示阴影
          isShadowed: false,
          selectable: false,
          shadowColor: 'rgba(0,0,0,0.5)',
          shadowBlur: 10,
          shadowOffset: new go.Point(1, 1),
          minSize: new go.Size(60, 102),
          click: function (e, node) {
            // 突出显示从给定Node出来的所有链接和节点
            var diagram = node.diagram
            self.diagram.nodes.map(node => {
              let pic = node.findObject('Picture')
              pic.source = node.jb.source
            })
            diagram.startTransaction('highlight')
            // 删除之前的所有突出显示
            diagram.clearHighlighteds()

            let checkedPic = node.findObject('Picture')
            node.isShadowed = true
            checkedPic.source = node.jb.hlSource
            self.setActiveLineColor(node)

            // 对于节点的每个节点目标，设置Node.isHighlighted
            node.findNodesOutOf().each((node) => {
              let pic = node.findObject('Picture')
              pic.source = node.jb.hlSource
              node.isShadowed = true
              self.setActiveLineColor(node)
            })
            node.findNodesInto().each((node) => {
              let pic = node.findObject('Picture')
              pic.source = node.jb.hlSource
              node.isShadowed = true
            })
            diagram.commitTransaction('highlight')
          }
        },
        // define the node's outer shape
        this.$(go.Panel, 'Vertical',
          {
            padding: new go.Margin(0, 0)
          },
          this.$(go.Panel, 'Position',
            {
              padding: new go.Margin(0, 0),
              desiredSize: new go.Size(68, 68)
            },
            this.$(go.Picture,
              {
                name: 'Picture',
                desiredSize: new go.Size(50, 50),
                margin: new go.Margin(10, 0, 10, 0),
                position: new go.Point(8, -2)
              },
              new go.Binding('source', 'source')
            ),

            this.$(go.Shape, 'Circle', {
              isPanelMain: true,
              fill: 'transparent',
              desiredSize: new go.Size(58, 58),
              position: new go.Point(0, 0),
              strokeWidth: 0,
              opacity: 0.6
            },
            new go.Binding('stroke', 'wranColor'),
            new go.Binding('strokeWidth', 'wranStroke')
            )
          ),
          // 定义节点上的文案
          this.$(go.TextBlock, {
            textAlign: 'center',
            margin: new go.Margin(10, 0, 10, 0),
            width: 100,
            font: '12px 微软雅黑',
            wrap: go.TextBlock.WrapFit
          },
          // 文案显示字段为 key 的变量中存储的值
          new go.Binding('text', 'key'),
          new go.Binding('stroke', 'textColor')
          ),
          this.$(go.TextBlock, {
            textAlign: 'center',
            width: 100,
            font: '12px 微软雅黑'
          },
          // 文案显示字段为 key 的变量中存储的值
          new go.Binding('text', 'key'),
          new go.Binding('stroke', 'textColor'))),
        { // this tooltip shows the name and picture of the kitten
          toolTip:
              this.$('ToolTip',
                { 'Border.fill': 'transparent',
                  'Border.strokeWidth': 0,
                  isShadowed: false
                },
                // 或者
                // new go.Binding("Border.fill", "color"),
                this.$(go.Panel, 'Position',
                  {
                    padding: new go.Margin(0, 0),
                    desiredSize: new go.Size(274, 269)
                  },
                  this.$(go.Picture,
                    {
                      name: 'Picture',
                      minSize: new go.Size(274, 269),
                      margin: new go.Margin(0, 0, 0, 0),
                      position: new go.Point(0, 0),
                      source: require('../../assets/changemachine/tooltip-bg.png')
                    }
                    // new go.Binding('source', 'isHighlighted', self.imageConverter).ofObject()
                  ),
                  this.$(go.Panel, 'Table', {
                    padding: new go.Margin(18, 18),
                    defaultAlignment: go.Spot.Left,
                    background: 'transparent',
                    position: new go.Point(0, 0)
                  },
                  this.$(go.RowColumnDefinition, {
                    column: 2,
                    row: 5
                  }),
                  this.$(go.Picture, {
                    row: 0,
                    column: 0,
                    desiredSize: new go.Size(60, 60),
                    margin: new go.Margin(0, 20, 0, 0)
                  },
                  new go.Binding('source', 'source')),
                  this.$(go.TextBlock, this.tooltipNameFont(), {
                    row: 0,
                    column: 1,
                    width: 160
                  },
                  new go.Binding('text', 'name').makeTwoWay()),
                  this.$(go.TextBlock, '设备IP：', this.tooltipLabelFont(), {
                    row: 1,
                    column: 0,
                    margin: new go.Margin(20, 20, 0, 0)
                  }),
                  this.$(go.TextBlock, this.tooltipValueFont(), {
                    row: 1,
                    column: 1,
                    margin: new go.Margin(20, 0, 0, 0)
                  },
                  new go.Binding('text', 'ip').makeTwoWay()),
                  this.$(go.TextBlock, '运行状态：', this.tooltipLabelFont(), {
                    row: 2,
                    column: 0,
                    margin: new go.Margin(20, 20, 0, 0)
                  }),
                  this.$(go.TextBlock, this.tooltipValueFont(), {
                    row: 2,
                    column: 1,
                    margin: new go.Margin(20, 0, 0, 0)
                  },
                  new go.Binding('text', 'state').makeTwoWay()),
                  this.$(go.TextBlock, '所在层级：', this.tooltipLabelFont(), {
                    row: 3,
                    column: 0,
                    margin: new go.Margin(20, 20, 0, 0)
                  }),
                  this.$(go.TextBlock, this.tooltipValueFont(), {
                    row: 3,
                    column: 1,
                    width: 160,
                    margin: new go.Margin(20, 0, 0, 0)
                  },
                  new go.Binding('text', 'layer').makeTwoWay()),
                  this.$(go.TextBlock, '节点设备：', this.tooltipLabelFont(), {
                    row: 4,
                    column: 0,
                    margin: new go.Margin(20, 20, 0, 0)
                  }),
                  this.$(go.TextBlock, this.tooltipValueFont(), {
                    row: 4,
                    column: 1,
                    width: 160,
                    margin: new go.Margin(20, 0, 0, 0)
                  },
                  new go.Binding('text', 'parent_name').makeTwoWay())
                  )
                )
              ) // end Adornment
        }
        )
    },
    // 设置连线样式
    setLinkStyle () {
      this.diagram.linkTemplate =
        this.$(go.Link, // the whole link panel
          {
            name: 'test',
            selectable: false,
            toShortLength: 0,
            fromShortLength: 0,
            toEndSegmentLength: 0,
            routing: go.Link.Orthogonal
            // curve: go.Link.JumpGap
          },
          // make sure links come in from the proper direction and go out appropriately
          new go.Binding('fromSpot', 'fromSpot', function (d) {
            return self.spotConverter(d)
          }),
          new go.Binding('toSpot', 'toSpot', function (d) {
            return self.spotConverter(d)
          }),
          new go.Binding('points').makeTwoWay(),
          // 使用ispanelmain:true标记每个形状以获取链接几何图形
          this.$(go.Shape, {
            name: 'SHAPE_BACKGROUND',
            isPanelMain: true,
            stroke: '#41BFEC' /* blue */,
            strokeWidth: 6
          },
          new go.Binding('stroke', 'lineColor')),
          this.$(go.Shape, {
            isPanelMain: true,
            stroke: 'white',
            strokeWidth: 2,
            name: 'PIPE',
            strokeDashArray: [20, 40]
          })
        ) // the link shape
      this.loop()
    },
    spotConverter (dir) {
      if (dir === 'left') return go.Spot.LeftSide
      if (dir === 'right') return go.Spot.RightSide
      if (dir === 'top') return go.Spot.TopSide
      if (dir === 'bottom') return go.Spot.BottomSide
      if (dir === 'rightsingle') return go.Spot.Right
    },
    // 线的动画
    loop () {
      var diagram = this.diagram
      setTimeout(() => {
        var oldskips = diagram.skipsUndoManager
        diagram.skipsUndoManager = true
        diagram.links.each((link) => {
          var shape = link.findObject('PIPE')
          var off = shape.strokeDashOffset - 3
          // animate (move) the stroke dash
          shape.strokeDashOffset = (off <= 0) ? 60 : off
        })
        diagram.skipsUndoManager = oldskips
        this.loop()
      }, 40)
    }
  }
}
</script>
<style lang="css" scoped>
html,
#app,
ul {
  background: #090b0c;
}
.topu {
  position: relative;
}
ul {
  margin: 0;
  padding: 0;
  list-style: none;
  position: absolute;
  left: 1px;
  top: 1px;
  width: 400px;
  height: 400px;
  background: #090b0c;
  z-index: 3;
}
</style>
